package cn.itcast.hiss.process.activiti.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.itcast.hiss.api.client.HissProcessConstants;
import cn.itcast.hiss.api.client.form.FormSubmitData;
import cn.itcast.hiss.api.client.processdefinition.ProcessDesignModel;
import cn.itcast.hiss.api.client.task.*;
import cn.itcast.hiss.api.server.common.UserInfo;
import cn.itcast.hiss.common.SystemConstant;
import cn.itcast.hiss.common.enums.HissTaskTypeEnum;
import cn.itcast.hiss.common.enums.ModelTypeEnum;
import cn.itcast.hiss.common.enums.ProcessStatusEnum;
import cn.itcast.hiss.form.mapper.HissDynamicTableMapper;
import cn.itcast.hiss.form.mapper.HissFormTablesMapper;
import cn.itcast.hiss.form.pojo.HissFormTables;
import cn.itcast.hiss.message.CurrentUser;
import cn.itcast.hiss.message.Message;
import cn.itcast.hiss.message.MessageContext;
import cn.itcast.hiss.message.sender.form.FormSubmitDataMessage;
import cn.itcast.hiss.message.sender.processdefinition.ProcessDesignModelMessage;
import cn.itcast.hiss.message.sender.task.*;
import cn.itcast.hiss.process.activiti.mapper.*;
import cn.itcast.hiss.process.activiti.multilnstance.AddMultiInstanceExecutionCmd;
import cn.itcast.hiss.process.activiti.multilnstance.AddSequenceMultiInstanceCmd;
import cn.itcast.hiss.process.activiti.multilnstance.JumpMultiInstanceExecutionCmd;
import cn.itcast.hiss.process.activiti.pojo.ActReModel;
import cn.itcast.hiss.process.activiti.pojo.HissProcessForm;
import cn.itcast.hiss.process.activiti.pojo.HissProcessPreLaunch;
import cn.itcast.hiss.process.activiti.pojo.HissProcessUpdateJob;
import cn.itcast.hiss.process.activiti.service.ActivitiService;
import cn.itcast.hiss.process.activiti.service.CommentService;
import cn.itcast.hiss.process.activiti.service.UserTaskService;
import cn.itcast.hiss.process.activiti.util.AdminUtil;
import cn.itcast.hiss.process.activiti.util.VariableUtil;
import cn.itcast.hiss.server.template.HissServerApperanceTemplate;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.model.Process;
import org.activiti.bpmn.model.*;
import org.activiti.engine.*;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior;
import org.activiti.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentBuilder;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.DelegationState;
import org.activiti.engine.task.IdentityLink;
import org.activiti.engine.task.Task;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/*
 * @author miukoo
 * @description 流程办理各功能实现
 * @date 2023/6/3 11:19
 * @version 1.0
 **/
@Slf4j
@Service
@Transactional
public class ActivitiServiceImpl implements ActivitiService {

    @Autowired
    HissProcessUpdateJobMapper hissProcessUpdateJobMapper;

    @Autowired
    private UserTaskService userTaskService;

    @Autowired
    private HissServerApperanceTemplate hissServerApperanceTemplate;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private GeBytearrayMapper geBytearrayMapper;

    @Autowired
    private HissProcessFormMapper hissProcessFormMapper;

    @Autowired
    private TaskService taskService;

    @Autowired
    private CommentService commentService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private HiActinstMapper hiActinstMapper;

    @Autowired
    private ManagementService managementService;

    @Autowired
    private ActReModelMapper actReModelMapper;
    @Autowired
    private HissDynamicTableMapper hissDynamicTableMapper;
    @Autowired
    private HissFormTablesMapper hissFormTablesMapper;
    @Autowired
    private HissProcessPreLaunchMapper hissProcessPreLaunchMapper;


    @Override
    public Set<String> doGetClientUserInfo(DelegateExecution execution, String assignee) {
        Set<String> resClientNames = new HashSet<>();
        Map<String, Object> variables = execution.getVariables();
        //判断是否是客户端变量--如果是客户端变量，那么就提取客户端请求信息
        if (VariableUtil.checkIsClientVariable(assignee)) {
            String[] varList = VariableUtil.getVariables(assignee);
            Object variableValue = variables.get(varList[0]);
            if (ObjectUtil.isNotNull(variableValue)) {
                //说明是流程变量
                if (variableValue.toString().startsWith(SystemConstant.CLIENT_FLAG)) {
                    //TODO 向客户端请求数据--需要获取流程发起人的信息
                    UserInfo userInfo = userTaskService.getBeforeNodeUserInfo(execution);
                    String[] split = variableValue.toString().split("/");
                    userInfo.setCurrentNodeVariable(split[1]);
                    userInfo.setCurrentNodeValue(varList[1]);
                    log.info("当前节点需要的用户信息:{},需要往客户端请求数据", assignee);
                    List<String> name = hissServerApperanceTemplate.getUserInfo(execution.getTenantId(), userInfo);
                    resClientNames.addAll(name);
                } else {
                    //说明是固定的值--不需要请求客户端
                    resClientNames.add(variableValue.toString());
                }
            } else {
                //虽然是变量 但客户端并未上报
                resClientNames.add(assignee);
            }
        } else {
            //不需要请求客户端直接添加
            resClientNames.add(assignee);
        }
        return resClientNames;
    }

    /**
     * 设计文件部署
     *
     * @param message
     * @param messageContext
     */
    @Override
    public void modelToDeploment(Message message, MessageContext messageContext) {
        ProcessDesignModel processDesignModel = (ProcessDesignModel) message.getPalyload();
        Model model = repositoryService.getModel(processDesignModel.getModelId());
        if (model != null) {
            Deployment deploy = modelToDeployment(model, message, messageContext);
            if (deploy == null) {// 发布有错误
                return;
            } else {
                messageContext.addResult("deployId", deploy.getId());
            }
        } else {
            messageContext.addError("msg", "未找到对应的model");
        }
    }

    /**
     * 通过model实现流程的启动
     *
     * @param message
     * @param messageContext
     * @param isInitForm 是否初始化表单数据
     */
    @Override
    public void startByModel(Message message, MessageContext messageContext,boolean isInitForm) {
        ProcessDesignModel processDesignModel = (ProcessDesignModel) message.getPalyload();
        Model model = repositoryService.getModel(processDesignModel.getModelId());
        if (model != null) {
            Deployment deploy = null;
            try{
                deploy = modelToDeployment(model, message, messageContext);
                if (deploy == null) {// 发布有错误
                    return;
                }
            }catch (ActivitiException e){
                e.printStackTrace();
                messageContext.addError("msg", "发布出错："+e.getMessage());
                return;
            }
            List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery()
                    .deploymentId(deploy.getId())
                    .active()
                    .processDefinitionTenantId(model.getTenantId())
                    .processDefinitionResourceName(HissProcessConstants.PROCESS_RUN_XML).list();
            ProcessDefinition processDefinition = null;
            if(list.size()==1){
                processDefinition = list.get(0);
            }else{
                for (ProcessDefinition definition : list) {
                    BpmnModel bpmnModel = repositoryService.getBpmnModel(definition.getId());
                    if(bpmnModel.getMainProcess().isExecutable()){
                        processDefinition = definition;
                        break;
                    }
                }
            }
            if (processDefinition != null) {
                HashMap<String, Object> variables = new HashMap<>();
                // 发起人信息作为流程变量
                variables.put(SystemConstant.TASK_VARIABLES_CREATE_USERID, message.getMessageAuth().getCurrentUser().getUserId());
                variables.put(SystemConstant.TASK_VARIABLES_CREATE_USERNAME, message.getMessageAuth().getCurrentUser().getUserName());
                // 存储前端自定义变量
                if (processDesignModel.getVariables() != null) {
                    variables.putAll(processDesignModel.getVariables());
                }
                // 设置用户ID
                Authentication.setAuthenticatedUserId(message.getMessageAuth().getCurrentUser().getUserId());
                ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinition.getId(), processDesignModel.getBusinessKey(), variables);
                String title = parseProcessName(model.getName(),message.getMessageAuth().getCurrentUser());
                addHissProcessUpdateJob(title,processInstance.getTenantId(),processInstance.getId(),10000);

                // 关联表单数据
                if(isInitForm) {
                    setProcessForm(model, processInstance.getTenantId(), processInstance.getProcessInstanceId(), null);
                }
                // 添加评论
                String content = String.format("%s发起了流程", message.getMessageAuth().getCurrentUser().getUserName());
                commentService.addComment(processInstance.getProcessInstanceId(), message.getMessageAuth().getCurrentUser().getUserId(), "流程开始", content);

                messageContext.addResultAndCount("processInstanceId", processInstance.getProcessInstanceId());
            } else {
                messageContext.addError("msg", "未找到对应的流程定义");
            }
        } else {
            messageContext.addError("msg", "未找到对应的model");
        }
    }

    /**
     * 设置流程使用到的表单信息
     * @param model
     * @param tenantId
     * @param processInstanceId
     * @param launchId
     */
    private void setProcessForm(Model model,String tenantId,String processInstanceId,String launchId){
        String modelConfigJson = geBytearrayMapper.getModelConfigJson(model.getId());
        if (StrUtil.isNotEmpty(modelConfigJson)) {
            JSONObject jsonObject = JSON.parseObject(modelConfigJson);
            if(jsonObject.containsKey("forms")){
                JSONArray forms = jsonObject.getJSONArray("forms");
                if(forms!=null){
                    for (int i = 0; i < forms.size(); i++) {
                        JSONObject form = forms.getJSONObject(i);
                        HissProcessForm hissProcessForm =  new HissProcessForm();
                        hissProcessForm.setFormId(form.getString("id"));
                        hissProcessForm.setFormName(form.getString("name"));
                        hissProcessForm.setFormType(form.getString("type"));
                        hissProcessForm.setNodeId(form.getString("nodeId"));
                        hissProcessForm.setTenantId(tenantId);
                        hissProcessForm.setProcessInstanceId(processInstanceId);
                        hissProcessForm.setLaunchId(launchId);
                        hissProcessForm.setCreatedTime(new Date());
                        hissProcessFormMapper.insert(hissProcessForm);
                    }
                }
            }
        }
    }

    private String parseProcessName(String name,CurrentUser currentUser){
        if(StrUtil.isNotEmpty(currentUser.getUserName())) {
            name = name.replace("[姓名]", currentUser.getUserName());
        }
        if(StrUtil.isNotEmpty(currentUser.getDeptName())) {
            name = name.replace("[部门]", currentUser.getDeptName());
        }
        if(StrUtil.isNotEmpty(currentUser.getRoleName())) {
            name = name.replace("[角色]", currentUser.getRoleName());
        }
        if(StrUtil.isNotEmpty(currentUser.getPostName())) {
            name = name.replace("[岗位]", currentUser.getPostName());
        }
        String date = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        name = name.replace("[日期]", date);
        String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("HHmmss"));
        name = name.replace("[时间]", time);
        return name;
    }

    /**
     * 模型发布
     *
     * @param model
     * @param message
     * @param messageContext
     */
    private Deployment modelToDeployment(Model model, Message message, MessageContext messageContext) {
        DeploymentBuilder deploymentBuilder = repositoryService.createDeployment()
                .key(model.getKey())
                .name(model.getName())
                .category(model.getCategory())
                .enableDuplicateFiltering()
                .tenantId(model.getTenantId());
        String modelConfigJson = geBytearrayMapper.getModelConfigJson(model.getId());
        if (StrUtil.isNotEmpty(modelConfigJson)) {
            deploymentBuilder.addBytes(HissProcessConstants.PROCESS_SHOW_CONFIG_JSON, modelConfigJson.getBytes());
        }
        deploymentBuilder.addBytes(HissProcessConstants.PROCESS_RUN_XML, repositoryService.getModelEditorSource(model.getId()));
        Deployment deploy = deploymentBuilder.deploy();
        model.setDeploymentId(deploy.getId());
        repositoryService.saveModel(model);
        return deploy;
    }

    @Override
    public void cancelTask(CancelTaskMessage params, MessageContext messageContext) {
        CancelTask cancelTask = params.getPalyload();
        Task task = taskService.createTaskQuery().taskId(cancelTask.getTaskId()).singleResult();
        if (task != null) {
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
            String userId = historicProcessInstance.getStartUserId();
            String currentUserId = params.getMessageAuth().getCurrentUser().getUserId();
            // 只有发起人能取消
            if (currentUserId.equals(userId)) {
                // 标记流程是否已经取消
                runtimeService.setVariable(task.getExecutionId(), HissProcessConstants.PROCESS_STATUS, ProcessStatusEnum.CANCEL.name());
                // 添加评论
                String comment = String.format("【%s】%s了流程", params.getMessageAuth().getCurrentUser().getUserName(), cancelTask.getOperatorName());
                commentService.addComment(task, params.getMessageAuth().getCurrentUser().getUserId(), comment, cancelTask.getReason());
                // 添加流程变量，表示任务被拒绝
                runtimeService.deleteProcessInstance(task.getProcessInstanceId(), cancelTask.getReason());
                messageContext.addResultAndCount("msg", "任务" + cancelTask.getOperatorName() + "成功");
            } else {
                messageContext.addError("msg", "你无权限" + cancelTask.getOperatorName() + "任务");
            }
        } else {
            messageContext.addError("msg", "任务未找到");
        }
    }

    @Override
    public void approveTask(ApproveTaskMessage params, MessageContext messageContext) {
        ApproveTask payload = params.getPalyload();
        String taskId = payload.getTaskId();
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (task != null) {
            CurrentUser currentUser = params.getMessageAuth().getCurrentUser();
            if (StrUtil.isNotEmpty(task.getAssignee()) && task.getAssignee().equalsIgnoreCase(currentUser.getUserId())) {
                String comment = String.format("%s【%s】", currentUser.getUserName(), payload.getOperatorName());
                commentService.addComment(task, currentUser.getUserId(), comment, StringUtils.isNotBlank(payload.getReason()) ? payload.getReason() : "");
                // 加载表单数据，并组织成流程变量
                List<HissProcessForm> processForms = hissProcessFormMapper.listFormByProcessInstanceId(task.getProcessInstanceId());
                if(processForms!=null){
                    for (HissProcessForm processForm : processForms) {
                        if(StrUtil.isNotEmpty(processForm.getDataId())) {
                            HissFormTables mainTable = hissFormTablesMapper.selectMainTable(processForm.getFormId());
                            Map<String, Object> data = hissDynamicTableMapper.getData(mainTable, processForm.getDataId());
                            Map<String, Object> variables = payload.getVariables();
                            if(variables==null){
                                variables = new HashMap<>();
                            }
                            variables.putAll(data);
                            payload.setVariables(variables);
                        }
                    }
                }
                if (task.getDelegationState() == DelegationState.PENDING) {
                    // 完成委派任务
                    taskService.resolveTask(taskId, payload.getVariables());
                }else {
                    taskService.complete(taskId, payload.getVariables());
                }
                log.info("完成任务：{}, 完成人{}", task.getName(), task.getAssignee());
                messageContext.addResultAndCount("msg", "任务" + payload.getOperatorName() + "成功");
            } else {
                messageContext.addError("msg", "你无权限" + payload.getOperatorName() + "任务");
            }
        } else {
            messageContext.addError("msg", "任务未找到");
        }
    }

    @Override
    public void rejectTask(RejectTaskMessage params, MessageContext messageContext) {
        RejectTask payload = params.getPalyload();
        Task task = taskService.createTaskQuery().taskId(payload.getTaskId()).singleResult();
        if (task != null) {
            CurrentUser currentUser = params.getMessageAuth().getCurrentUser();
            if (StrUtil.isNotEmpty(task.getAssignee()) && task.getAssignee().equalsIgnoreCase(currentUser.getUserId())) {
                String comment = String.format("%s【%s】", currentUser.getUserName(), payload.getOperatorName());
                commentService.addComment(task, currentUser.getUserId(), comment, StringUtils.isNotBlank(payload.getReason()) ? payload.getReason() : "");
                //如果是并行多实例节点，则直不允许加签
                boolean isParallelMultiInstance = isParallelMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey());
                if (isParallelMultiInstance) {
                    //如果是并行多实例节点，则不删除流程
                    complateTaskButNotDeleteProcess(task, payload);
                    messageContext.addResultAndCount("msg", "任务" + payload.getOperatorName() + "成功");
                } else {
                    // 标记流程是否已经拒绝
                    runtimeService.setVariable(task.getExecutionId(), HissProcessConstants.PROCESS_STATUS, ProcessStatusEnum.REJECT.name());
                    // 添加流程变量，表示任务被拒绝
                    runtimeService.deleteProcessInstance(task.getProcessInstanceId(), "任务被" + payload.getOperatorName() + ":" + payload.getReason());
                    messageContext.addResultAndCount("msg", "任务" + payload.getOperatorName() + "成功");
                }
            }else{
                messageContext.addError("msg", "你无权限" + payload.getOperatorName() + "任务");
            }
        } else {
            messageContext.addError("msg", "任务未找到");
        }
    }

    @Override
    public void rollBackTask(AnyJumpTaskMessage params, MessageContext messageContext, boolean first) {
        AnyJumpTask palyload = params.getPalyload();
        Task task = taskService.createTaskQuery().taskId(palyload.getTaskId()).singleResult();
        String operatorName = palyload.getOperatorName();
        if (task != null) {
            CurrentUser currentUser = params.getMessageAuth().getCurrentUser();
            if (StrUtil.isNotEmpty(task.getAssignee()) && task.getAssignee().equalsIgnoreCase(currentUser.getUserId())) {
                String processDefinitionId = task.getProcessDefinitionId();
                BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
                Process process = bpmnModel.getMainProcess();
                String activityId = getTargetActivityId(process,task,palyload,first);
                if (StrUtil.isEmpty(activityId)) {
                    messageContext.addError("msg", operatorName + "节点信息未找到");
                    return;
                }
                if (activityId.equals(task.getTaskDefinitionKey())) {
                    messageContext.addError("msg", "不能" + operatorName + "到自己节点");
                    return;
                }
                completeTask(process, task, palyload, currentUser, activityId, operatorName);
                messageContext.addResultAndCount("msg", operatorName + "成功");
            }else{
                messageContext.addError("msg", "你无权限" + operatorName + "任务");
            }
        } else {
            messageContext.addError("msg", "任务未找到");
        }
    }

    @Override
    public void delegateTask(DelegateTaskMessage params, MessageContext messageContext) {
        DelegateTask delegateTask = params.getPalyload();
        Task task = taskService.createTaskQuery().taskId(delegateTask.getTaskId()).singleResult();
        if (task != null) {
            if (StrUtil.isNotEmpty(task.getAssignee()) && task.getAssignee().equalsIgnoreCase(params.getMessageAuth().getCurrentUser().getUserId())) {
                try {
                    String taskId = delegateTask.getTaskId();
                    String assignee = delegateTask.getUserId();
                    String comment = String.format("%s【%s】", params.getMessageAuth().getCurrentUser().getUserName(), delegateTask.getOperatorName());
                    commentService.addComment(task, params.getMessageAuth().getCurrentUser().getUserId(), comment, "任务被"+delegateTask.getOperatorName()+"给"+delegateTask.getUserName());
                    // 指派任务给指定用户
                    taskService.delegateTask(taskId, assignee);
                    messageContext.addResultAndCount("msg", "任务" + delegateTask.getOperatorName() + "成功");
                } catch (Exception e) {
                    messageContext.addError("msg", "任务" + delegateTask.getOperatorName() + "失败");
                }
            } else {
                messageContext.addError("msg", "你无权限" + delegateTask.getOperatorName() + "任务");
            }
        } else {
            messageContext.addError("msg", "任务未找到");
        }
    }

    @Override
    public void claimTask(TaskMessage params, MessageContext messageContext) {
        HissTask hissTask = params.getPalyload();
        Task task = taskService.createTaskQuery().taskId(hissTask.getTaskId()).singleResult();
        if (task != null) {
            if (StrUtil.isEmpty(task.getAssignee())) {
                List<IdentityLink> identityLinks = runtimeService.getIdentityLinksForProcessInstance(task.getProcessInstanceId());
                boolean isOk = false;
                CurrentUser currentUser = params.getMessageAuth().getCurrentUser();
                if (identityLinks != null) {
                    Set<String> userGroup = new HashSet<>();
                    if (StrUtil.isNotEmpty(currentUser.getUserGroups())) {
                        userGroup.addAll(Arrays.asList(currentUser.getUserGroups().split(",")));
                    }
                    for (IdentityLink identityLink : identityLinks) {
                        if (StrUtil.isNotEmpty(identityLink.getUserId()) && identityLink.getUserId().equals(currentUser.getUserId())) {// 是否是候选者
                            isOk = true;
                            break;
                        }
                        if (StrUtil.isNotEmpty(identityLink.getGroupId()) && userGroup.size() > 0 &&userGroup.contains(identityLink.getGroupId())) {// 是否是候选组
                            isOk = true;
                            break;
                        }
                    }
                }
                if (!isOk) {
                    messageContext.addError("msg", "无权限" + hissTask.getOperatorName() + "任务");
                    return;
                }
                taskService.claim(hissTask.getTaskId(), currentUser.getUserId());
                // 添加认领评论
                String comment = String.format("【%s】%s了任务", currentUser.getUserName(), hissTask.getOperatorName());
                commentService.addComment(task, params.getMessageAuth().getCurrentUser().getUserId(), comment, "");
                messageContext.addResultAndCount("msg", "任务" + hissTask.getOperatorName() + "成功");
            } else {
                messageContext.addError("msg", "任务已经被" + hissTask.getOperatorName());
            }
        } else {
            messageContext.addError("msg", "任务未找到");
        }
    }

    /**
     * 归还任务
     *
     * @param params
     * @param messageContext
     */
    @Override
    public void unclaimTask(TaskMessage params, MessageContext messageContext) {
        HissTask hissTask = params.getPalyload();
        Task task = taskService.createTaskQuery().taskId(hissTask.getTaskId()).singleResult();
        if (task != null) {
            CurrentUser currentUser = params.getMessageAuth().getCurrentUser();
            if (StrUtil.isNotEmpty(task.getAssignee()) && task.getAssignee().equalsIgnoreCase(currentUser.getUserId())) {
                taskService.unclaim(hissTask.getTaskId());
                // 添加认领评论
                String comment = String.format("【%s】%s了任务", currentUser.getUserName(), hissTask.getOperatorName());
                commentService.addComment(task, params.getMessageAuth().getCurrentUser().getUserId(), comment, "");
                messageContext.addResultAndCount("msg", "任务" + hissTask.getOperatorName() + "成功");
            } else {
                messageContext.addError("msg", "你无权限" + hissTask.getOperatorName());
            }
        } else {
            messageContext.addError("msg", "任务未找到");
        }
    }

    @Override
    public void beforeSignTask(AddExecutionTaskMessage params, MessageContext messageContext) {
        AddExecutionTask addExecutionTask = params.getPalyload();
        Task task = taskService.createTaskQuery().taskId(addExecutionTask.getTaskId()).singleResult();
        if(task!=null){
            String processInstanceId = task.getProcessInstanceId();
            String processDefinitionId = task.getProcessDefinitionId();
            boolean sequentialMultiInstance = isSequentialMultiInstance(processDefinitionId, task.getTaskDefinitionKey());
            CurrentUser currentUser = params.getMessageAuth().getCurrentUser();
            if (StrUtil.isNotEmpty(task.getAssignee()) && task.getAssignee().equalsIgnoreCase(currentUser.getUserId())) {
                if (sequentialMultiInstance) {
                    //如果是串行多实例节点，则需要先完成当前任务，再加签
                    AddSequenceMultiInstanceCmd addSequenceMultiInstanceCmd = new AddSequenceMultiInstanceCmd(task.getId(), runtimeService.getVariables(task.getExecutionId()), addExecutionTask.getUserId(), addExecutionTask.getUserName(), taskService);
                    managementService.executeCommand(addSequenceMultiInstanceCmd);
                    String userName = params.getMessageAuth().getCurrentUser().getUserName();
                    taskService.addComment(task.getId(), processInstanceId, userName + "加签【" + String.join(",", addExecutionTask.getUserName()) + "】");
                    taskService.complete(task.getId(), addExecutionTask.getVariables());
                    messageContext.addResultAndCount("msg", addExecutionTask.getOperatorName() + "成功");
                }else{
                    messageContext.addError("msg", "只有串行多实例支持"+addExecutionTask.getOperatorName());
                }
            }else {
                messageContext.addError("msg", "你无权限" + addExecutionTask.getOperatorName());
            }
        }else{
            messageContext.addError("msg", "任务未找到");
        }
    }

    @Override
    public void doParallelSignTask(AddExecutionTaskMessage params, MessageContext messageContext) {
        AddExecutionTask addExecutionTask = params.getPalyload();
        Task task = taskService.createTaskQuery().taskId(addExecutionTask.getTaskId()).singleResult();
        if(task!=null){
            String processInstanceId = task.getProcessInstanceId();
            String processDefinitionId = task.getProcessDefinitionId();
            boolean parallelMultiInstance = isParallelMultiInstance(processDefinitionId, task.getTaskDefinitionKey());
            CurrentUser currentUser = params.getMessageAuth().getCurrentUser();
            if (StrUtil.isNotEmpty(task.getAssignee()) && task.getAssignee().equalsIgnoreCase(currentUser.getUserId())) {
                if (parallelMultiInstance) {
                    String userName = params.getMessageAuth().getCurrentUser().getUserName();
                    taskService.addComment(task.getId(), processInstanceId, userName + "加签【" + String.join(",", addExecutionTask.getUserName()) + "】");
                    //如果是串行多实例节点，则需要先完成当前任务，再加签
                    AddMultiInstanceExecutionCmd addMultiInstanceExecutionCmd = new AddMultiInstanceExecutionCmd(task.getId(), runtimeService.getVariables(task.getExecutionId()), addExecutionTask.getUserId(), addExecutionTask.getUserName(), taskService);
                    managementService.executeCommand(addMultiInstanceExecutionCmd);
                    messageContext.addResultAndCount("msg", addExecutionTask.getOperatorName() + "成功");
                }else{
                    messageContext.addError("msg", "只有并行多实例支持"+addExecutionTask.getOperatorName());
                }
            }else {
                messageContext.addError("msg", "你无权限" + addExecutionTask.getOperatorName());
            }
        }else{
            messageContext.addError("msg", "任务未找到");
        }
    }

    @Override
    public void createNotificationTask(NotificationTaskMessage params, MessageContext messageContext) {
        NotificationTask notificationTask = params.getPalyload();
        String actionName = notificationTask.getOperatorName();
        Task task = taskService.createTaskQuery().taskId(notificationTask.getTaskId()).singleResult();
        if (task != null) {
            CurrentUser currentUser = params.getMessageAuth().getCurrentUser();
            if (StrUtil.isNotEmpty(task.getAssignee()) && task.getAssignee().equalsIgnoreCase(currentUser.getUserId())) {
                HissTaskTypeEnum type = HissTaskTypeEnum.NOTIFICATION;
                ActReModel actReModel = actReModelMapper.getModelByBusId(type.name().toLowerCase());
                ProcessDefinition hissNotification = repositoryService.createProcessDefinitionQuery()
                        .processDefinitionName("hiss_"+type.name().toLowerCase())
                        .deploymentId(actReModel.getDeploymentId())
                        .processDefinitionTenantId("tenant_hiss")
                        .latestVersion().singleResult();
                // 增加流程标识
                Map<String,Object> map = new HashMap<>();
                map.put(type.name().toLowerCase(),notificationTask.getUserId());
                map.put(HissProcessConstants.PARENT_PROCESS_INSTANCE,task.getProcessInstanceId());// 这里把原流程实例与当前知会流程绑定
                map.put(HissProcessConstants.NODE_TYPE, type.name());// 设置类型
                Authentication.setAuthenticatedUserId(task.getAssignee());
                ProcessInstance processInstance = runtimeService.startProcessInstanceById(hissNotification.getId(), task.getBusinessKey(), map);
                ProcessInstance oldProcessInstance = runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
                addHissProcessUpdateJob("【"+actionName+"】"+oldProcessInstance.getName(),task.getTenantId(),processInstance.getId(),10000);
                // 添加评论
                String comment = String.format("【%s】%s了%s", currentUser.getUserName(), actionName, notificationTask.getUserName());
                commentService.addComment(task, currentUser.getUserId(), comment, "");
                messageContext.addResult("msg", actionName + "成功");
            } else {
                messageContext.addError("msg", "你无权限" + actionName);
            }
        } else {
            messageContext.addError("msg", "任务未找到");
        }
    }

    @Override
    public void startPreProcessByModel(Message message, MessageContext messageContext) {
        ProcessDesignModel processDesignModel = (ProcessDesignModel) message.getPalyload();
        Model model = repositoryService.getModel(processDesignModel.getModelId());
        if (model != null) {
            if (StrUtil.isEmpty(model.getDeploymentId())) {
                messageContext.addError("msg", "只有部署后的流程才可以发起预备流程");
                return;
            }
            HissProcessPreLaunch launch = new HissProcessPreLaunch();
            launch.setBusinessKey(processDesignModel.getBusinessKey());
            launch.setModelId(model.getId());
            launch.setTenantId(model.getTenantId());
            launch.setModelName(parseProcessName(model.getName(),message.getMessageAuth().getCurrentUser()));
            launch.setUserId(message.getMessageAuth().getCurrentUser().getUserId());
            launch.setUserName(message.getMessageAuth().getCurrentUser().getUserName());
            launch.setCreatedTime(new Date());
            hissProcessPreLaunchMapper.insert(launch);
            // 初始化表单
            setProcessForm(model,launch.getTenantId(),null,""+launch.getId());
            messageContext.addResultAndCount("preProcessInstanceId", launch.getId());
        } else {
            messageContext.addError("msg", "未找到对应的model");
        }
    }

    @Override
    public void sendPreProcess(FormSubmitDataMessage params, MessageContext messageContext) {
        FormSubmitData palyload = params.getPalyload();
        if(StrUtil.isNotEmpty(palyload.getModelId())){
            HissProcessPreLaunch launch = hissProcessPreLaunchMapper.selectById(palyload.getModelId());
            if(launch!=null){
                if(launch.getUserId().equals(params.getMessageAuth().getCurrentUser().getUserId())){
                    // 如果前端有变更的数据，需要重置到流程变量中
                    Map variables = new HashMap();
                    // 加载表单数据，并组织成流程变量
                    List<HissProcessForm> processForms = hissProcessFormMapper.listFormByLaunchId(launch.getId());
                    if(processForms!=null){
                        for (HissProcessForm processForm : processForms) {
                            if(StrUtil.isNotEmpty(processForm.getDataId())) {
                                HissFormTables mainTable = hissFormTablesMapper.selectMainTable(processForm.getFormId());
                                Map<String, Object> data = hissDynamicTableMapper.getData(mainTable, processForm.getDataId());
                                variables.putAll(data);
                            }
                        }
                    }
                    // 发起流程
                    ProcessDesignModel processDesignModel = new ProcessDesignModel();
                    processDesignModel.setModelId(launch.getModelId());
                    processDesignModel.setVariables(variables);
                    ProcessDesignModelMessage processDesignModelMessage = new ProcessDesignModelMessage();
                    processDesignModelMessage.setMessageAuth(params.getMessageAuth());
                    processDesignModelMessage.setPalyload(processDesignModel);
                    MessageContext tempMessageContext = new MessageContext();
                    startByModel(processDesignModelMessage,tempMessageContext,false);
                    if(tempMessageContext.isSuccess()){
                        String processInstanceId = (String) tempMessageContext.getResult().get("processInstanceId");
                        // 把预备表单的数据迁移到流程上
                        hissProcessFormMapper.updateLaunchToProcessInstance(launch.getId(),processInstanceId,launch.getTenantId());
                        // 删除预备流程信息
                        hissProcessPreLaunchMapper.deleteById(launch);
                        messageContext.addResultAndCount("processInstanceId", processInstanceId);
                    }else{
                        messageContext.setError(tempMessageContext.getError());
                    }
                }else{
                    messageContext.addError("msg","无权限操作");
                }
            }else{
                messageContext.addError("msg","未找到对应的预备流程");
            }
        }else{
            messageContext.addError("msg","未找到对应的预备流程");
        }
    }

    private void addHissProcessUpdateJob(String title,String tenantId,String processInstanceId,int delay){
        HissProcessUpdateJob job = new HissProcessUpdateJob();
        job.setName(title);
        job.setDelay(delay);
        job.setTenantId(tenantId);
        job.setProcessInstanceId(processInstanceId);
        job.setCreatedTime(new Date());
        job.setExecutedTime(new Date(System.currentTimeMillis()+delay));
        hissProcessUpdateJobMapper.insert(job);
    }

    /**
     * 完成当前的所有任务
     * @param process
     * @param task
     * @param palyload
     * @param currentUser
     * @param activityId
     * @param operatorName
     */
    private void completeTask(Process process, Task task,AnyJumpTask palyload,CurrentUser currentUser,String activityId, String operatorName){
        List<Task> list = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).list();
        for (Task t : list) {
            FlowNode curFlowNode = (FlowNode) process.getFlowElement(t.getTaskDefinitionKey());
            List<SequenceFlow> tempOutgoingSequenceFlows = curFlowNode.getOutgoingFlows();
            // 如果是当前审批节点，则进行驳回处理
            if(t.getId().equals(task.getId())){
                List<SequenceFlow> targetSequenceFlow = getTargetSequenceFlow(process, activityId);
                curFlowNode.setOutgoingFlows(targetSequenceFlow);
                String comment = String.format("%s%s流程", currentUser.getUserName(), operatorName);
                commentService.addComment(task, currentUser.getUserId(), comment, StringUtils.isNotBlank(palyload.getReason()) ? palyload.getReason() : "");
                // 判读是否为多实例节点的跳转
                boolean isMulti = false;
                if(curFlowNode!=null){
                    if(curFlowNode instanceof UserTask){
                        UserTask userTask = (UserTask)curFlowNode;
                        MultiInstanceLoopCharacteristics loopCharacteristics = userTask.getLoopCharacteristics();
                        if(loopCharacteristics!=null){
                            isMulti = true;
                            managementService.executeCommand(new JumpMultiInstanceExecutionCmd(targetSequenceFlow,task));
                        }
                    }
                }
                if(!isMulti){
                    taskService.complete(palyload.getTaskId());
                }
            }else{
                // 如果是同级的节点，则静默完成
                curFlowNode.setOutgoingFlows(new ArrayList<>());
                taskService.complete(t.getId());
                // 删除在历史活动和任务表中的数据——也可以不删除，删除了在前端悬浮提示上体验好一点
                historyService.deleteHistoricTaskInstance(t.getId());
                hiActinstMapper.deleteHiActivityInstByTaskId(t.getId());
            }
            curFlowNode.setOutgoingFlows(tempOutgoingSequenceFlows);
        }
    }

    private List<SequenceFlow> getTargetSequenceFlow(Process process ,String activityId){
        FlowNode targetFlowNode = (FlowNode) process.getFlowElement(activityId);
        List<SequenceFlow> incomingFlows = targetFlowNode.getIncomingFlows();
        List<SequenceFlow> result = new ArrayList<>();
        for (SequenceFlow incomingFlow : incomingFlows) {
            FlowElement source = incomingFlow.getSourceFlowElement();
            if(source instanceof Gateway){
                Gateway gateway = (Gateway)source;
                result.addAll(gateway.getOutgoingFlows());
            }
        }
        if(result.size()==0){
            return incomingFlows;
        }
        return result;
    }

    private String getTargetActivityId(Process process,Task task ,AnyJumpTask palyload, boolean first){
        String jumpTaskOrActivityId = palyload.getJumpTaskOrActivityId();
        if(StrUtil.isEmpty(jumpTaskOrActivityId)){
            FlowElement flowElement = process.getFlowElement(task.getTaskDefinitionKey());
            FlowElement prevFlowElement = getParentUserTaskFlowElement(flowElement);
            if(!first){
                // 返回上一个节点
                if(prevFlowElement!=null){
                    jumpTaskOrActivityId = prevFlowElement.getId();
                }
            }else{
                // 获取第一个节点的ID
                FlowElement firseFlowElement = prevFlowElement;
                while (true){
                    prevFlowElement = getParentUserTaskFlowElement(prevFlowElement);
                    if(prevFlowElement!=null){
                        firseFlowElement = prevFlowElement;
                    }else{
                        break;
                    }
                }
                // 返回第一个节点
                if(firseFlowElement!=null){
                    jumpTaskOrActivityId = firseFlowElement.getId();
                }
            }
        }
        return jumpTaskOrActivityId;
    }

    /**
     * 递归找到上一个节点
     * @param element
     * @return
     */
    private FlowElement getParentUserTaskFlowElement(FlowElement element){
        if(element!=null && element instanceof FlowNode){
            FlowNode flowNode = (FlowNode) element;
            List<SequenceFlow> incomingFlows = flowNode.getIncomingFlows();
            if(incomingFlows!=null&&incomingFlows.size()>0){
                // 默认选中第一个返回
                SequenceFlow sequenceFlow = incomingFlows.get(0);
                FlowElement sourceFlowElement = sequenceFlow.getSourceFlowElement();
                if(sourceFlowElement instanceof UserTask){
                    return sourceFlowElement;
                }else{
                    return getParentUserTaskFlowElement(sourceFlowElement);
                }
            }
        }
        return null;
    }


    private boolean isParallelMultiInstance(String processDefinitionId, String taskDefinitionKey) {
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(taskDefinitionKey);
        if (flowNode.getBehavior() instanceof ParallelMultiInstanceBehavior) {
           return true;
        }
        return false;
    }

    private boolean isSequentialMultiInstance(String processDefinitionId, String taskDefinitionKey) {
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(taskDefinitionKey);
        if (flowNode.getBehavior() instanceof SequentialMultiInstanceBehavior) {
            return true;
        }
        return false;
    }

    private void complateTaskButNotDeleteProcess(Task task, RejectTask payload) {
        Map<String, Object> variables = runtimeService.getVariables(task.getExecutionId());
        //在流程变量中获取拒绝的流程实例数
        Integer complateNumber = (Integer) variables.getOrDefault(SystemConstant.REJECT_INSTANCES,0);
        runtimeService.setVariable(task.getExecutionId(), SystemConstant.REJECT_INSTANCES, ++complateNumber);
        // 审批意见
        taskService.complete(task.getId(), payload.getVariables());
    }

}
